<template>
  <div class="filter" v-loading="loading">
    <h4 class="title sle" v-if="title">{{ title }}</h4>
    <el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable v-if="needSearch" />
    <el-scrollbar
      :style="{
        height: needSearch ? (title ? `calc(100% - 95px)` : `calc(100% - 56px)`) : title ? `calc(100% - 40px)` : `calc(100% - 0)`
      }"
    >
      <el-tree
        ref="treeRef"
        :default-expand-all="false"
        :default-expanded-keys="defaultExpandedKeys"
        :render-after-expand="false"
        :node-key="id"
        :data="multiple ? treeData : treeAllData"
        :show-checkbox="multiple"
        :check-strictly="false"
        :current-node-key="!multiple ? selected : ''"
        :highlight-current="!multiple"
        :expand-on-click-node="onlyLeafNodeHighlight"
        :check-on-click-node="multiple"
        :props="defaultProps"
        :filter-node-method="filterNode"
        :default-checked-keys="multiple ? selected : []"
        @node-click="handleNodeClick"
        @node-expand="handleNodeExpand"
        @check="handleCheckChange"
      >
        <template #default="scope">
          <span class="el-tree-node__label">
            <slot :row="scope">
              {{ scope.node.pointCol }}
              <span
                class="statusPoint"
                v-show="scope.node.data.showPonit"
                :style="{ background: scope.node.data.pointCol }"
              ></span>
              <el-tooltip class="box-item" effect="light" :content="scope.node.label" placement="top-start">
                <span>{{ scope.node.label }}</span>
              </el-tooltip>
            </slot>
          </span>
        </template>
      </el-tree>
    </el-scrollbar>
  </div>
</template>

<script setup lang="ts" name="TreeFilter">
import { ref, watch, onBeforeMount, nextTick, onMounted } from "vue";
import { ElTree } from "element-plus";
// 接收父组件参数并设置默认值
interface TreeFilterProps {
  requestApi?: (data?: any) => Promise<any>; // 请求分类数据的 api ==> 非必传
  data?: { [key: string]: any }[]; // 分类数据，如果有分类数据，则不会执行 api 请求 ==> 非必传
  title?: string; // treeFilter 标题 ==> 非必传
  id?: string; // 选择的id ==> 非必传，默认为 “id”
  label?: string; // 显示的label ==> 非必传，默认为 “label”T
  multiple?: boolean; // 是否为多选 ==> 非必传，默认为 false
  defaultValue?: any; // 默认选中的值 ==> 非必传
  needSearch?: boolean; // 是否支持搜索 ==> 非必传
  onlyLeafNodeHighlight?: boolean; // 只有叶子节点（没有子元素的节点）高亮 ==> 非必传
  defaultExpandedKeys?: string[];
}

const props = withDefaults(defineProps<TreeFilterProps>(), {
  id: "id",
  label: "label",
  disabled: "disabled",
  multiple: false,
  needSearch: true,
  onlyLeafNodeHighlight: false
});

const defaultProps = {
  children: "children",
  label: props.label,
  disabled: props.disabled
};

const loading = ref(false);

const treeRef = ref<InstanceType<typeof ElTree>>();
const treeData = ref<{ [key: string]: any }[]>([]);
const treeAllData = ref<{ [key: string]: any }[]>([]);
const curHighlight = ref<any>("");

const selected = ref();
const setSelected = (currentNodeKey?: undefined) => {
  if (props.multiple) selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue];
  else
    selected.value = !currentNodeKey
      ? typeof props.defaultValue === "string" || typeof props.defaultValue === "number"
        ? props.defaultValue
        : ""
      : currentNodeKey;
};

const isSelNodeExpanded = ref(false);

onBeforeMount(async () => {
  setSelected();

  if (props.requestApi) {
    const { data } = await props.requestApi!();
    treeData.value = data;
    treeAllData.value = [...data];
  }
});

onMounted(() => {
  !props.multiple && (curHighlight.value = props.defaultValue || "");
});

// 使用 nextTick 防止打包后赋值不生效，开发环境是正常的
watch(
  () => props.defaultValue,
  () => nextTick(() => setSelected()),
  { deep: true, immediate: true }
);

watch(
  () => props.data,
  () => {
    if (props.data?.length) {
      treeData.value = props.data;
      treeAllData.value = [...props.data];
    }
  },
  { deep: true, immediate: true }
);

let timer: any = null;
const filterText = ref("");
watch(filterText, val => {
  if (timer !== null) clearTimeout(timer);
  timer = setTimeout(() => {
    loading.value = true;
    setTimeout(function () {
      treeRef.value!.filter(val);
      loading.value = false;
      timer = null;
    }, 1500);
  }, 100);
});

// 过滤
const filterNode = (value: string, data: { [key: string]: any }, node: any) => {
  if (!value) return true;
  let parentNode = node.parent,
    labels = [node.label],
    level = 1;
  while (level < node.level) {
    labels = [...labels, parentNode.label];
    parentNode = parentNode.parent;
    level++;
  }
  return labels.some(label => label.indexOf(value) !== -1);
};

interface FilterEmits {
  (e: "change", value: any): void;
}
const emit = defineEmits<FilterEmits>();

// 单选
const handleNodeClick = (data: { [key: string]: any }, Node: any) => {
  if (props.multiple) return;
  if (data.children?.length) {
    const isChild = data.children.some((item: { id: any }) => {
      return item.id === curHighlight.value;
    });

    Node.isCurrent = false;
    // 值更改，触发watch
    selected.value = "";
    if (isChild) {
      if (Node.expanded) {
        isSelNodeExpanded.value = true;
        nextTick(() => {
          setSelected(curHighlight.value);
        });
      } else {
        isSelNodeExpanded.value = false;
      }
    } else {
      if (isSelNodeExpanded.value) {
        // 还原之前的高亮节点
        nextTick(() => {
          setSelected(curHighlight.value);
        });
      }
    }
    return;
  }

  !props.multiple && (curHighlight.value = data.id);

  emit("change", data[props.id]);
};
// 展开
const handleNodeExpand = (data: { [key: string]: any }, Node: any) => {
  if (props.multiple) return;
  if (data.children?.length) {
    const isChild = data.children.some((item: { id: any }) => {
      return item.id === curHighlight.value;
    });
    Node.isCurrent = false;
    // 值更改，触发watch
    selected.value = "";
    if (isChild) {
      if (Node.expanded) {
        isSelNodeExpanded.value = true;
        setSelected(curHighlight.value);
      } else {
        isSelNodeExpanded.value = false;
      }
    } else {
      if (isSelNodeExpanded.value) {
        // 还原之前的高亮节点
        nextTick(() => {
          setSelected(curHighlight.value);
        });
      }
    }
    return;
  }
};

// 多选
const handleCheckChange = (data: any, nodes: any) => {
  emit("change", { data, nodes });
};

// 暴露给父组件使用
defineExpose({ treeData, treeAllData, treeRef });
</script>

<style scoped lang="scss">
@import "./index.scss";
</style>
